#include "controller.h"

node* stack_head;
node* stack_tail;
int cmdcount;

void cgetline(char* buffer, ssize_t size, FILE* fp)
{
    buffer[0] = fgetc(fp);
    int i = 0;
    for(; i < size-1 && buffer[i] != EOF && buffer[i] != '\n'; buffer[++i] = fgetc(fp));
    buffer[i] = '\0';
}

void nCleanup(node* target)
{
    if(target == NULL)return;
    node* next = target->right;
    while(target != NULL)
    {
        free(target);
        target = next;
        next = next -> right;
    }
}

node* initnode(int key)
{
    node* newnode = (node*)malloc(sizeof(node));
    if(newnode == NULL)return NULL;
    newnode->left = newnode->right = NULL;
    newnode->key = key;
    return newnode;
}

void cPush(int key)
{
    nCleanup(stack_head->right);
    stack_head->right = initnode(key);
    if(stack_head->right == NULL)return;
    cmdcount++;
    stack_head->right->left = stack_head;
    stack_head = stack_head -> right;
}

int cPop()
{
    if(stack_head == NULL)return CEUndefinedError;
    else{
        cmdcount--;
        stack_head = stack_head -> left;
        return stack_head -> right -> key;
    }
}

int cmdtype(char* cmd)
{
    if(strcmp(cmd, "left") == 0) return LEFT;
    else if(strcmp(cmd, "right") == 0) return RIGHT;
    else if(strcmp(cmd, "up") == 0)return UP;
    else if(strcmp(cmd, "down") == 0)return DOWN;
    else if(strcmp(cmd, "revy") == 0 || strcmp(cmd, "revertY") == 0)return REVY;
    else if(strcmp(cmd, "revx") == 0 || strcmp(cmd, "revertX") == 0)return REVX;
    else if(strcmp(cmd, "random") == 0)return CRND;
    else if(*cmd == 's')return SWAP;
    else if(strcmp(cmd, "undo") == 0)return UNDO;
    else if(strcmp(cmd, "exit") == 0)return EXIT;
    else if(strcmp(cmd, "save") == 0)return SAVE;
    return UNKNOWN;
}

void typeexec(cpny_t* cpny,int type)
{
    if(type == LEFT)cshl(cpny);
    else if(type == RIGHT)cshr(cpny);
    else if(type == UP)cshu(cpny);
    else if(type == DOWN)cshd(cpny);
    else if(type == REVX)revertX(cpny);
    else if(type == REVY)revertY(cpny);
}

error_t cexec(char* cmd, cpny_t* cpny)
{
    int type = cmdtype(cmd);
    typeexec(cpny, type);
    if(type == LEFT || type == RIGHT || type == UP || type == DOWN)cPush(-type);
    else if(type == REVX || type == REVY)cPush(type);
    else if(type == UNDO){
        if(cmdcount == 0)return CEBadArgument;
        else{
            typeexec(cpny, stack_head->key);
            stack_head = stack_head->left;
            free(stack_head->right);
            stack_head->right = NULL;
            cmdcount--;
        }
    }else if(type == SAVE){
        FILE* fp = fopen("list.txt","w");
        cdisplay(cpny->column, cpny->row, fp, cpny);
    }else if(type == EXIT){
        
    }
    return CESuccess;
}

error_t initController(cpny_t* cpny)
{
    if(cpny == NULL)return CEBadArgument;
    cmdcount = 0;
    stack_head = stack_tail = initnode(UNKNOWN);
    char* cmd = (char*)calloc(BUFFSIZE, sizeof(char));
    do
    {
        display(cpny);
        printf("\n\n> ");
        cgetline(cmd, BUFFSIZE, stdin);
    }while(cexec(cmd, cpny) != CEExit);
    nCleanup(stack_tail);
    cdealloc(cpny);
    return CESuccess;
}